/*
 * Copyright (C) 2007-2008  Hylke van der Schaaf
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, in version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
package hextd.server;

import com.usoog.tdcore.TDCore;
import com.usoog.tdcore.UserInfo;
import com.usoog.tdcore.message.Message;
import com.usoog.tdcore.message.MessageFetch;
import com.usoog.tdcore.message.MessageGameJoin;
import com.usoog.tdcore.message.MessageReplay;
import com.usoog.tdcore.message.MessageUnknown;
import com.usoog.tdcore.message.MessageUserAuth;
import com.usoog.tdcore.message.MessageUserInfo;
import com.usoog.tdcore.network.LineListener;
import com.usoog.tdcore.network.NetworkConnection;
import java.util.HashMap;
import java.util.Map;

public class ServerUser implements LineListener {

	/**
	 * Commands are used to encapsulate code into something that can be put in a
	 * Map
	 */
	private interface MessageCommand {

		public void execute(Message message);
	}
	/**
	 * The map of commands per message
	 */
	private Map<String, MessageCommand> messageCommands = new HashMap<String, MessageCommand>();
	private Server server;
	private Channel channel;
	private boolean authenticated = false;
	private NetworkConnection connection;
	private int gameId = 0;
	private boolean ready = false;
	private UserInfo userInfo;

	public ServerUser(Server server) {
		this.server = server;
		makeMessageCommands();
	}

	public void setConnection(NetworkConnection connection) {
		this.connection = connection;
		this.connection.addLineListener(this);
	}

	public Channel getChannel() {
		return channel;
	}

	public void setChannel(Channel channel) {
		this.channel = channel;
		this.ready = false;
	}

	public void doAuth(String token) {
		System.out.println("Player::doAuth: doing auth for '" + token + "'");
		authenticated = server.authenticatePlayer(this, token);
		if (authenticated) {
			sendLine(MessageUserInfo.formatMessage(TDCore.SERVER_ID, userInfo));
		}
	}

	public boolean isAuthenticated() {
		return authenticated;
	}

	public void setAuthenticated(boolean authenticated) {
		this.authenticated = authenticated;
	}

	public NetworkConnection getConnection() {
		return connection;
	}

	public void sendLine(String line) {
		this.connection.sendLine(line);
	}

	private void makeMessageCommands() {
		messageCommands.put(MessageUserAuth.key, new MessageCommand() {

			public void execute(Message message) {
				MessageUserAuth mua = (MessageUserAuth) message;
				doAuth(mua.getToken());
			}
		});
		messageCommands.put(MessageGameJoin.key, new MessageCommand() {

			public void execute(Message message) {
				if (isAuthenticated()) {
					MessageGameJoin mjc = (MessageGameJoin) message;
					server.playerToChannel(ServerUser.this, mjc.getId());
				}
			}
		});
		messageCommands.put(MessageReplay.key, new MessageCommand() {

			public void execute(Message message) {
				MessageReplay mrl = (MessageReplay) message;
				mrl.setSenderId(userInfo.userId);
				server.addSpReplay(mrl);
			}
		});
		messageCommands.put(MessageFetch.key, new MessageCommand() {

			public void execute(Message message) {
				MessageFetch mf = (MessageFetch) message;
				server.fetchFromServer(mf, ServerUser.this);
			}
		});
		messageCommands.put(MessageUserInfo.key, new MessageCommand() {

			public void execute(Message message) {
				MessageUserInfo mpi = (MessageUserInfo) message;
				if (userInfo != null) {
					userInfo.updateFrom(mpi.getUserInfo(), false);
				}
			}
		});
		messageCommands.put(MessageUnknown.key, new MessageCommand() {

			public void execute(Message message) {
				MessageUnknown mu = (MessageUnknown) message;
				System.out.println("ServerUser::lineReceived: Unknown message: " + mu.getMess());
			}
		});
	}

	@Override
	public void lineReceived(String line) {
		Message message = Server.messageFactory.parseString(line);
		if (this.channel != null) {
			this.channel.receiveMessage(this, message);
		} else {
			MessageCommand command = messageCommands.get(message.getKey());
			if (command != null) {
				command.execute(message);
			} else {
				System.err.println("ServerUser::lineReceived: Unhandled message type: " + message.getKey());
			}
		}
	}

	@Override
	public void inputStopped() {
		if (channel != null) {
			channel.playerLeft(this, "nowhere (Disconnected)");
			channel = null;
		}
		connection.removeLineListener(this);
		server.playerDisconnected(this);
	}

	public int getGameId() {
		return gameId;
	}

	public void setGameId(int gameId) {
		this.gameId = gameId;
	}

	public int getUserId() {
		return userInfo.userId;
	}

	public String getUserName() {
		return userInfo.name;
	}

	public String getUserRights() {
		return userInfo.userRights;
	}

	public int getRank() {
		return userInfo.rank;
	}

	public int getGames() {
		return userInfo.games;
	}

	public boolean isReady() {
		return ready;
	}

	public void setReady(boolean ready) {
		this.ready = ready;
	}

	public UserInfo getUserInfo() {
		return userInfo;
	}

	public void setUserInfo(UserInfo userInfo) {
		this.userInfo = userInfo;
	}
}
